#ifndef PORTABLE_TRANSFORMER_H_
#define PORTABLE_TRANSFORMER_H_
#include <iostream>
#include <string_view>

#include "include/v8-version.h"
#include "src/ast/scopes.h"
#include "src/base/logging.h"
#include "src/codegen/compiler.h"
#include "src/codegen/script-details.h"
#include "src/execution/isolate.h"
#include "src/interpreter/bytecode-array-builder.h"
#include "src/numbers/conversions.h"
#include "src/objects/elements-kind.h"
#include "src/objects/feedback-vector.h"
#include "src/objects/fixed-array.h"
#include "src/objects/literal-objects-inl.h"
#include "src/objects/literal-objects.h"
#include "src/objects/shared-function-info-inl.h"
#include "src/objects/template-objects.h"
#include "src/pbc/portable-format-helper.h"
#include "src/pbc/portable-format.h"
#include "src/pbc/transform/portable-bytecode-lower.h"
#include "src/pbc/transform/portable-transformer-base.h"

namespace v8 {
namespace internal {
using namespace portable;

#if V8_MAJOR_VERSION == 11
using TrustedFixedArray = FixedArray;
using TrustedByteArray = ByteArray;
#endif

class PbcTransformer : public PbcTransformerBase {
 public:
  // todo(hh):refactor code for lazy so that no need filename
  explicit PbcTransformer(const PbcScript& script, i::Isolate& v8Isolate,
                          bool lazy_transform,
                          std::string filename = "output.pbc",
                          std::string dummy_source = "/*pbc*/")
      : PbcTransformerBase(script, v8Isolate, Handle<i::Script>()),

        lazy_transform_(lazy_transform),
        filename_(filename),
        dummy_source_(dummy_source) {
    func_data_vec_.resize(pbc_script_.NumberOfFunctions(),
                          Handle<SharedFunctionInfo>());
    scope_data_vec_.resize(pbc_script_.NumberOfScopes(),
                           Handle<i::ScopeInfo>());
    // InitScopeTable();
    if (i::v8_flags.log_pbc && lazy_transform_) {
      std::cout << "==============lazy transform==============\n";
    }
    DCHECK(dummy_source.starts_with(dummy_prefix_));
  }

  Handle<SharedFunctionInfo> Run();

 private:
  // void InitScopeTable();
  Handle<ScopeInfo> GetOrTransformScope(uint32_t scope_id) override;
  Handle<SharedFunctionInfo> TransformFunction(uint32_t func_id) override;
  Handle<BytecodeArray> TransformBytecode(uint32_t func_id) override;
  Handle<TrustedFixedArray> TransformConstantPool(uint32_t func_id) override;
#if 0
  Handle<TrustedByteArray> TransformExceptionTable(uint32_t func_id)override;
  Handle<FeedbackMetadata> TransformFeedbackMeta(uint32_t func_id) override;
#endif

  Handle<SharedFunctionInfo> GetOrCreateFuncData(uint32_t func_id) override;

  bool IsFuncTransformed(uint32_t func_id);

  bool IsTopLevelFunction(uint32_t func_id) const {
    return pbc_script_.GetTopLevelFuncId() == func_id;
  }

  Handle<SharedFunctionInfo> GetFuncData(uint32_t func_id) {
    return func_data_vec_[func_id];
  }

  Handle<ScopeInfo> GetScopeInfoFromPbcScope(uint32_t scope_id) {
    DCHECK(scope_id != ScopeRef::Invalid().GetScopeId());
    DCHECK(scope_id < scope_data_vec_.size());
    return scope_data_vec_[scope_id];
  }

#if V8_MAJOR_VERSION == 11
  inline void setScriptFromSfi(Handle<SharedFunctionInfo> sfi) {
    Handle<Script> script(Script::cast(sfi->script()), &isolate_);
    script_ = script;
  }
#else
  inline void setScriptFromSfi(DirectHandle<SharedFunctionInfo> sfi) {
    Handle<Script> script(Cast<Script>(sfi->script()), &isolate_);
    script_ = script;
  }
#endif

  inline void initScriptInfo(Handle<WeakFixedArray> infos) {
#if V8_MAJOR_VERSION == 11
    script_->set_shared_function_infos(*infos);
#else
    script_->set_infos(*infos);
#endif
  }

  // const PbcScript& pbc_script_;
  // // TODO:(wwq) LocalIsolate
  // Isolate& isolate_;
  // Handle<Script> script_;
  // Zone zone_;
  // AstValueFactory ast_factory_;
  std::vector<Handle<SharedFunctionInfo>> func_data_vec_;  // index is funcId
  std::vector<Handle<ScopeInfo>> scope_data_vec_;          // index is scopeId
  std::vector<uint32_t> functions_to_transform_;
  // Handle<FixedArray> top_declarations_;
  bool lazy_transform_{false};
  const std::string filename_;
  const std::string dummy_source_;
};

}  // namespace internal
}  // namespace v8

#endif  // PORTABLE_TRANSFORMER_H_
